package com.zxw.gateway.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zxw.common.entity.gateway.GatewayEntity;
import com.zxw.common.entity.gateway.GatewayListQuery;
import com.zxw.common.entity.gateway.GatewayQuery;
import com.zxw.common.entity.gateway.GatewayVO;
import com.zxw.gateway.mapper.GatewayMapper;
import com.zxw.gateway.service.GatewayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zhanxuewei
 * @since 2022-06-13
 */
@Service
@Slf4j
public class GatewayServiceImpl extends ServiceImpl<GatewayMapper, GatewayEntity> implements GatewayService, ApplicationEventPublisherAware {

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher publisher;

    @Override
    @Autowired
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }

    /**
     * 添加
     *
     * @param gatewayQuery GatewayQuery
     * @return 是否成功 true|false
     */
    @Override
    public boolean save(GatewayQuery gatewayQuery) {
        GatewayEntity gatewayEntity = new GatewayEntity();
        BeanUtils.copyProperties(gatewayQuery, gatewayEntity);
        return super.save(gatewayEntity);
    }

    /**
     * 批量添加
     *
     * @param list List<GatewayQuery>
     * @return 是否成功 true|false
     */
    @Override
    public boolean saveBatch(List<GatewayQuery> list) {
        List<GatewayEntity> collect = list.stream().map(item -> {
            GatewayEntity gatewayEntity = new GatewayEntity();
            BeanUtils.copyProperties(item, gatewayEntity);
            return gatewayEntity;
        }).collect(Collectors.toList());
        return super.saveBatch(collect);
    }

    /**
     * 根据ID集合批量删除
     *
     * @param ids id集合
     * @return 是否成功 true|false
     */
    @Override
    public boolean removeByIds(List<String> ids) {
        return super.removeByIds(ids);
    }

    /**
     * 根据ID修改
     *
     * @param gatewayQuery GatewayQuery
     * @return 是否成功 true|false
     */
    @Override
    public boolean updateById(GatewayQuery gatewayQuery) {
        GatewayEntity gatewayEntity = new GatewayEntity();
        BeanUtils.copyProperties(gatewayQuery, gatewayEntity);
        return super.updateById(gatewayEntity);
    }

    /**
     * 根据ID查询数据
     *
     * @param id ID
     * @return GatewayDO
     */
    @Override
    public GatewayEntity getById(String id) {
        return super.getById(id);
    }

    /**
     * 条件分页查询
     *
     * @param gatewayListQuery GatewayListQuery
     * @return IPage<GatewayDO>
     */
    @Override
    public IPage<GatewayEntity> list(GatewayListQuery gatewayListQuery) {
        IPage<GatewayEntity> pageInfo = new Page<>(gatewayListQuery.getCurrent(), gatewayListQuery.getSize());
        QueryWrapper<GatewayEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(GatewayEntity::getStatus, 1)
                .orderByDesc(GatewayEntity::getCreateTime);
        return super.page(pageInfo, queryWrapper);
    }

    @Override
    public void initAllRoute() {
        List<GatewayEntity> gatewayDOList = super.list();
        for (GatewayEntity gw : gatewayDOList) {
            System.out.println(gw);
            loadRoute(gw);
        }
    }

    @Override
    public IPage<GatewayVO> queryList(GatewayListQuery gatewayListQuery) {
        IPage<GatewayEntity> page = this.list(gatewayListQuery);
        return page.convert(new Function<GatewayEntity, GatewayVO>() {
            @Override
            public GatewayVO apply(GatewayEntity gatewayEntity) {
                GatewayVO gatewayVO = new GatewayVO();
                BeanUtils.copyProperties(gatewayEntity, gatewayVO);
                return gatewayVO;
            }
        });
    }

    @Override
    public GatewayVO detail(String id) {
        GatewayEntity gatewayEntity = this.getById(id);
        if (Objects.nonNull(gatewayEntity)) {
            GatewayVO gatewayVO = new GatewayVO();
            BeanUtils.copyProperties(gatewayEntity, gatewayVO);
            return gatewayVO;
        }
        return null;
    }

    public String loadRoute(GatewayEntity gatewayEntity) {
        RouteDefinition definition = new RouteDefinition();
        Map<String, String> predicateParams = new HashMap<>(8);
        PredicateDefinition predicate = new PredicateDefinition();
        FilterDefinition filterDefinition = new FilterDefinition();
        Map<String, String> filterParams = new HashMap<>(8);
        // 如果配置路由type为0的话 则从注册中心获取服务
        URI uri;
        if (gatewayEntity.getRouteType().equals("0")) {
            uri = UriComponentsBuilder.fromUriString("lb://" + gatewayEntity.getRouteUrl() + "/").build().toUri();
        } else {
            uri = UriComponentsBuilder.fromHttpUrl(gatewayEntity.getRouteUrl()).build().toUri();
        }

        //路由转发地址
        predicateParams.put("pattern", gatewayEntity.getRoutePattern());
        predicate.setName("Path");
        predicate.setArgs(predicateParams);

        // 名称是固定的, 路径去前缀
        filterParams.put("_genkey_0", gatewayEntity.getFilters());
        filterDefinition.setName("StripPrefix");
        filterDefinition.setArgs(filterParams);

        // 定义的路由唯一的id
        definition.setId(String.valueOf(gatewayEntity.getId()));
        definition.setUri(uri);
        definition.setPredicates(Arrays.asList(predicate));
        definition.setFilters(Arrays.asList(filterDefinition));

        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return "success";
    }

}
